import { getCode } from '@/utils';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import dayjs from 'dayjs';
import { JvmService } from './jvm.service';

export interface SandWalletDto {
  orderNo: string;
  orderAmt: string;
  ip: string;
  notifyUrl: string;
  returnUrl: string;
  goodsName?: string;
  extra?: string;
}

export interface SandRechargeDto {
  orderNo: string;
  orderAmt: string;
  ip: string;
  notifyUrl: string;
  returnUrl: string;
  goodsName?: string;
  extra?: string;
}

export interface SandOrderDto {
  orderNo: string;
  orderAmt: string;
  ip: string;
  notifyUrl: string;
  returnUrl: string;
  goodsName?: string;
  extra?: string;
}

@Injectable()
export class SandService {
  private readonly notifyUrl: string;
  private readonly returnUrl: string;
  private readonly merCustId: string;
  private readonly pfxFilePath: string;
  private readonly pfxPassword: string;
  private readonly cerFilePath: string;
  private readonly publicKey: any;
  private readonly privateKey: any;
  private readonly sand: any;
  private readonly configLoader: any;

  constructor(
    private readonly config: ConfigService,
    private readonly jvmService: JvmService,
  ) {
    this.notifyUrl = this.config.get('sand.notifyUrl');
    this.returnUrl = this.config.get('sand.returnUrl');
    this.merCustId = this.config.get('sand.merCustId');
    this.pfxFilePath = this.config.get('sand.pfxFilePath');
    this.pfxPassword = this.config.get('sand.pfxPassword');
    this.cerFilePath = this.config.get('sand.cerFilePath');

    // this.sand = this.jvmService.import('com.openx.Sand');
    // this.publicKey = this.sand.loadPublicKeySync(
    //   process.cwd() + this.cerFilePath,
    // );
    // this.sand.initPrivateKeySync(
    //   process.cwd() + this.pfxFilePath,
    //   this.pfxPassword,
    // );
    // this.privateKey = this.sand.getPrivateKeySync();
    // this.configLoader = this.jvmService.import(
    //   'cn.com.sand.ceas.sdk.config.ConfigLoader',
    // );
  }

  get NotifyUrl() {
    return this.notifyUrl;
  }

  get ReturnUrl() {
    return this.returnUrl;
  }

  async generateOrderNo() {
    return `${dayjs().format('YYYYMMDDHHmmss')}${await getCode(11)}`;
  }

  async wallet({
    orderNo,
    orderAmt,
    ip,
    notifyUrl,
    returnUrl,
    goodsName,
    extra,
  }: SandWalletDto): Promise<any> {
    return new Promise((r) => {
      ip = ip.replaceAll('.', '_');
      const currentTime = dayjs();
      const createTime = currentTime.format('YYYYMMDDHHmmss');
      const endTime = currentTime.add(1, 'hours').format('YYYYMMDDHHmmss');
      const version = '10';

      const LinkedHashMap = this.jvmService.import('java.util.LinkedHashMap');
      const map = new LinkedHashMap();
      map.putSync('accsplit_flag', 'NO');
      map.putSync('create_ip', ip);
      map.putSync('create_time', createTime);
      map.putSync('mer_no', this.merCustId);
      map.putSync('mer_order_no', orderNo);
      map.putSync('notify_url', notifyUrl);
      map.putSync('pay_extra', extra);
      map.putSync('order_amt', orderAmt);
      map.putSync('return_url', returnUrl);
      map.putSync('sign_type', 'RSA');
      map.putSync('store_id', '000000');
      map.putSync('version', version);

      const content = this.sand.getSignContentSync(map);
      const sign = this.sand.signSync(content, this.privateKey);
      const url =
        'https://faspay-oss.sandpay.com.cn/pay/h5/cloud?' +
        'version=' +
        version +
        '&mer_no=' +
        this.merCustId +
        '&mer_order_no=' +
        orderNo +
        '&create_time=' +
        createTime +
        '&expire_time=' +
        endTime +
        '&order_amt=' +
        orderAmt +
        '&notify_url=' +
        encodeURIComponent(notifyUrl) +
        '&return_url=' +
        encodeURIComponent(returnUrl) +
        '&create_ip=' +
        ip +
        '&goods_name=' +
        encodeURIComponent(goodsName) +
        '&store_id=' +
        '000000' +
        '&product_code=00000001' +
        '&clear_cycle=3' +
        '&pay_extra=' +
        encodeURIComponent(extra) +
        '&meta_option=%5B%7B%22s%22%3A%22Android%22,%22n%22%3A%22wxDemo%22,%22id%22%3A%22com.pay.paytypetest%22,%22sc%22%3A%22com.pay.paytypetest%22%7D%5D' +
        '&accsplit_flag=NO' +
        '&jump_scheme=' +
        '&sign_type=RSA' +
        '&sign=' +
        encodeURIComponent(sign);
      r({
        no: orderNo,
        url,
      });
    });
  }

  async recharge({
    orderNo,
    orderAmt,
    ip,
    notifyUrl,
    returnUrl,
    goodsName,
    extra,
  }: SandRechargeDto): Promise<any> {
    return new Promise((r) => {
      ip = ip.replaceAll('.', '_');
      const currentTime = dayjs();
      const createTime = currentTime.format('YYYYMMDDHHmmss');
      const endTime = currentTime.add(1, 'hours').format('YYYYMMDDHHmmss');
      const version = '10';

      const LinkedHashMap = this.jvmService.import('java.util.LinkedHashMap');
      const map = new LinkedHashMap();
      map.putSync('accsplit_flag', 'NO');
      map.putSync('create_ip', ip);
      map.putSync('create_time', createTime);
      map.putSync('mer_no', this.merCustId);
      map.putSync('mer_order_no', orderNo);
      map.putSync('notify_url', notifyUrl);
      map.putSync('pay_extra', extra);
      map.putSync('order_amt', orderAmt);
      map.putSync('return_url', returnUrl);
      map.putSync('sign_type', 'RSA');
      map.putSync('store_id', '000000');
      map.putSync('version', version);

      const content = this.sand.getSignContentSync(map);
      const sign = this.sand.signSync(content, this.privateKey);
      const url =
        'https://sandcash.mixienet.com.cn/pay/h5/unionpayh5?' +
        'version=' +
        version +
        '&mer_no=' +
        this.merCustId +
        '&mer_order_no=' +
        orderNo +
        '&create_time=' +
        createTime +
        '&expire_time=' +
        endTime +
        '&order_amt=' +
        orderAmt +
        '&notify_url=' +
        encodeURIComponent(notifyUrl) +
        '&return_url=' +
        encodeURIComponent(returnUrl) +
        '&create_ip=' +
        ip +
        '&goods_name=' +
        encodeURIComponent(goodsName) +
        '&store_id=' +
        '000000' +
        '&product_code=06030001' +
        '&clear_cycle=3' +
        '&pay_extra=' +
        encodeURIComponent(extra) +
        '&meta_option=%5B%7B%22s%22%3A%22Android%22,%22n%22%3A%22wxDemo%22,%22id%22%3A%22com.pay.paytypetest%22,%22sc%22%3A%22com.pay.paytypetest%22%7D%5D' +
        '&accsplit_flag=NO' +
        '&jump_scheme=' +
        '&sign_type=RSA' +
        '&sign=' +
        encodeURIComponent(sign);
      r({
        no: orderNo,
        url,
      });
    });
  }

  async order({
    orderNo,
    orderAmt,
    ip,
    notifyUrl,
    returnUrl,
    goodsName,
    extra,
  }: SandOrderDto): Promise<any> {
    return new Promise((r) => {
      ip = ip.replaceAll('.', '_');
      const currentTime = dayjs();
      const createTime = currentTime.format('YYYYMMDDHHmmss');
      const endTime = currentTime.add(1, 'hours').format('YYYYMMDDHHmmss');
      const version = '10';

      const LinkedHashMap = this.jvmService.import('java.util.LinkedHashMap');
      const map = new LinkedHashMap();
      map.putSync('accsplit_flag', 'NO');
      map.putSync('create_ip', ip);
      map.putSync('create_time', createTime);
      map.putSync('mer_no', this.merCustId);
      map.putSync('mer_order_no', orderNo);
      map.putSync('notify_url', notifyUrl);
      map.putSync('pay_extra', extra);
      map.putSync('order_amt', orderAmt);
      map.putSync('return_url', returnUrl);
      map.putSync('sign_type', 'RSA');
      map.putSync('store_id', '000000');
      map.putSync('version', version);

      const content = this.sand.getSignContentSync(map);
      const sign = this.sand.signSync(content, this.privateKey);
      const url =
        'https://faspay-oss.sandpay.com.cn/pay/h5/cloud?' +
        'version=' +
        version +
        '&mer_no=' +
        this.merCustId +
        '&mer_order_no=' +
        orderNo +
        '&create_time=' +
        createTime +
        '&expire_time=' +
        endTime +
        '&order_amt=' +
        orderAmt +
        '&notify_url=' +
        encodeURIComponent(notifyUrl) +
        '&return_url=' +
        encodeURIComponent(returnUrl) +
        '&create_ip=' +
        ip +
        '&goods_name=' +
        encodeURIComponent(goodsName) +
        '&store_id=' +
        '000000' +
        '&product_code=04010003' +
        '&clear_cycle=3' +
        '&pay_extra=' +
        encodeURIComponent(extra) +
        '&meta_option=%5B%7B%22s%22%3A%22Android%22,%22n%22%3A%22wxDemo%22,%22id%22%3A%22com.pay.paytypetest%22,%22sc%22%3A%22com.pay.paytypetest%22%7D%5D' +
        '&accsplit_flag=NO' +
        '&jump_scheme=' +
        '&sign_type=RSA' +
        '&sign=' +
        encodeURIComponent(sign);
      r({
        no: orderNo,
        url,
      });
    });
  }

  async query(no: string, productId: string = '06030001') {
    const content = {
      head: {
        version: '1.0',
        method: 'sandpay.trade.query',
        productId,
        accessType: '1',
        mid: this.merCustId,
        channelType: '07',
        reqTime: dayjs().format('YYYYMMDDHHmmss'),
      },
      body: {
        orderCode: no,
      },
    };
    const data = JSON.stringify(content);
    const sign = this.sand.signSync(data, this.privateKey);
    return await axios
      .post(
        `https://cashier.sandpay.com.cn/gateway/api/order/query`,
        {
          charset: 'utf-8',
          data,
          signType: '01',
          sign,
        },
        {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
          },
        },
      )
      .then((res) => {
        const params = new URLSearchParams(decodeURIComponent(res.data));
        const sign = params.get('sgin');
        const data = params.get('data');
        return JSON.parse(data);
      })
      .catch((e) => console.log(e));
  }

  async queryC2C(no: string): Promise<any> {
    return new Promise(async (r) => {
      const customerOrderNo = await this.generateOrderNo();
      const content = {
        mid: this.merCustId,
        customerOrderNo,
        oriCustomerOrderNo: no,
      };
      const encryptData = JSON.parse(
        this.sand.encryptSync(JSON.stringify(content), this.publicKey),
      );
      const data = { mid: this.merCustId, customerOrderNo, ...encryptData };
      const sign = await this.sand.signSync(
        JSON.stringify({
          mid: this.merCustId,
          customerOrderNo,
          ...encryptData,
        }),
        this.privateKey,
      );
      const params = {
        ...data,
        sign,
        signType: 'SHA1WithRSA',
      };
      await axios
        .post(
          `https://cap.sandpay.com.cn/v4/electrans/ceas.elec.trans.info.query`,
          params,
          {
            headers: {
              'Content-Type': 'application/json',
            },
          },
        )
        .then((res) => {
          r(res.data);
        })
        .catch((e) => console.log(e));
    });
  }
}
